package org.mm.web.controller;

import static org.mm.parameter.enm.EnumRole.ROLE_PATIENT;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.mm.dto.LinkDTO;
import org.mm.frame.support.SupportHandler;
import org.mm.model.Patient;
import org.mm.model.User;
import org.mm.service.MessageService;
import org.mm.service.PatientService;
import org.mm.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@RequestMapping("/")
@Controller
public class SecurityController {

	private final Logger log = LoggerFactory.getLogger(SecurityController.class);

	@Autowired
	private SupportHandler supportHandler;
	
	@Autowired
	private UserService userService;
	
	@Autowired
	private PatientService patientService;
	
	@Autowired
	public MessageService messageService;

	@RequestMapping(method = RequestMethod.GET)
	public ModelAndView enter(HttpServletRequest request, HttpServletResponse response) {
		log.debug("this is a enter");		
		return checkHomeUser(request, response);
	}

	@RequestMapping(value = "/homeUser", method = RequestMethod.GET)
	public ModelAndView checkHomeUser(HttpServletRequest request, HttpServletResponse response) {
		log.debug("checkHomeUser");			
		SecurityContext context = SecurityContextHolder.getContext();
		Authentication authentication = context.getAuthentication();
		HttpSession session = request.getSession();
		String viewName = "home";
		String userLabel = "";
		Patient patient = null;
		List<LinkDTO> links = null;
		if (authentication == null || authentication.getName().equals("anonymousUser")) {
			viewName = "home";
		} else {
			try {
				UserDetails userDetails = getUserDetails();
				String userName = userDetails.getUsername();
				userLabel = userName;
				User user = userService.findByUserName(userName);
				userLabel = user.getUserFirstName() + " " + user.getUserLastName();
				if (hasRole(ROLE_PATIENT.name)) {
					patient = patientService.findByParentUserId(user.getUserId());
					viewName = "homePatient";
					links = buildPatientLinks(response.getLocale());
					session.setAttribute("patient", patient);
					session.setAttribute("links", links);
					session.setAttribute("userLabel", userLabel);
				} else {
					viewName = "homeDoctor";
					//TODO links
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		ModelAndView mv = new ModelAndView(viewName);
		//mv.addObject("links", links);
		//mv.addObject("userLabel", userLabel);
		
		return mv;
	}

	@RequestMapping("/logout")
	public String logout() {
		log.debug("this is a logout");
		return "home";
	}

	@RequestMapping("/loginfail")
	public String loginFail(Model uiModel, Locale locale) {
		log.debug("Login failed detected");
		uiModel.addAttribute("message", supportHandler.retrieveMessage("login.failed.error", null, locale));
		return "home";
	}
	
	protected boolean hasRole(String role) {
		List<String> roles = new ArrayList<String>();
		roles.add(role);
		return hasRole(roles);
	}	
	
	/**
	 * @return true if the user has one of the specified roles.
	 */
	protected boolean hasRole(List<String> roles) {
	    boolean result = false;
	    Iterator<? extends GrantedAuthority> iteratorGA = SecurityContextHolder.getContext().getAuthentication().getAuthorities().iterator();
	    while (iteratorGA.hasNext() && !result) {
	    	GrantedAuthority authority = iteratorGA.next();
	    	String userRole = authority.getAuthority();
	        Iterator<String> iteratorRole = roles.iterator();
	        while (iteratorRole.hasNext() && !result) {
	        	String role = iteratorRole.next();
	            result =  role.equals(userRole);
	        }
	    }
	    return result;
	}	

	/**
	 * Get info about currently logged in user
	 * 
	 * @return UserDetails if found in the context, null otherwise
	 */
	protected UserDetails getUserDetails() {
		Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
		UserDetails userDetails = null;
		if (principal instanceof UserDetails) {
			userDetails = (UserDetails) principal;
		}
		return userDetails;
	}
	
	private List<LinkDTO> buildPatientLinks(Locale locale) {
		List<LinkDTO> links = new ArrayList<LinkDTO>();
		LinkDTO link0 = new LinkDTO(messageService.getMessageSource().getMessage("home.patient.therapy.title", null, locale), "/therapy");
		links.add(link0);
		LinkDTO link1 = new LinkDTO(messageService.getMessageSource().getMessage("home.patient.sensor.title", null, locale), "/sensor");
		links.add(link1);
		LinkDTO link2 = new LinkDTO(messageService.getMessageSource().getMessage("home.patient.doctor.title", null, locale), "/doctor");
		links.add(link2);		
		return links;
	}

/*	*//**
	 * Check if a role is present in the authorities of current user
	 * 
	 * @param authorities
	 *            all authorities assigned to current user
	 * @param role
	 *            required authority
	 * @return true if role is present in list of authorities assigned to
	 *         current user, false otherwise
	 *//*
	private boolean isRolePresent(Collection<GrantedAuthority> authorities, String role) {
		boolean isRolePresent = false;
		for (GrantedAuthority grantedAuthority : authorities) {
			isRolePresent = grantedAuthority.getAuthority().equals(role);
			if (isRolePresent)
				break;
		}
		return isRolePresent;
	}*/
}
